home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / png / ptot / ptot.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-29  |  15.9 KB  |  662 lines

  1. /*
  2.  * ptot.c
  3.  *
  4.  * Convert PNG (Portable Network Graphic) file to TGA (Truevision
  5.  * TGA File Format). Takes a filename argument on the command line.
  6.  *
  7.  **********
  8.  *
  9.  * HISTORY
  10.  *
  11.  * 95-03-10 Created by Lee Daniel Crocker <lee@piclab.com>
  12.  *          http://www.piclab.com/piclab/index.html
  13.  */
  14.  
  15. #include <stdlib.h>
  16. #include <stdio.h>
  17. #include <stdarg.h>
  18. #include <string.h>
  19. #include <ctype.h>
  20. #include <math.h>
  21.  
  22. #include "ptot.h"
  23.  
  24. #define DEFINE_ENUMS
  25. #include "errors.h"
  26. #define DEFINE_STRINGS
  27. #include "errors.h"
  28.  
  29. PNG_STATE ps = {0}; /* Referenced by tempfile.c, etc. */
  30.  
  31. char *keyword_table[N_KEYWORDS] = {
  32.     "Author", "Copyright", "Software", "Source", "Title"
  33. };
  34.  
  35. /*
  36.  * Local definitions and statics
  37.  */
  38.  
  39. static int decode_chunk(void);
  40. static int decode_IHDR(void);
  41. static int decode_PLTE(void);
  42. static int decode_gAMA(void);
  43. static int decode_tRNS(void);
  44. static int decode_cHRM(void);
  45. static int decode_pHYs(void);
  46. static int decode_oFFs(void);
  47. static int decode_sCAL(void);
  48. static int skip_chunk_data(void);
  49. static int validate_image(IMG_INFO *);
  50.  
  51. /*
  52.  * Main for PTOT.  Get filename from command line, massage the
  53.  * extensions as necessary, and call the read/write routines.
  54.  */
  55.  
  56. int
  57. main(
  58.     int argc,
  59.     char *argv[])
  60. {
  61.     int err;
  62.     FILE *fp;
  63.     char *cp, infname[FILENAME_MAX], outfname[FILENAME_MAX];
  64.     IMG_INFO *image;
  65.  
  66.     image = (IMG_INFO *)malloc((size_t)IMG_SIZE);
  67.     if (NULL == image) error_exit(ERR_MEMORY);
  68.  
  69.     if (argc < 2) error_exit(ERR_USAGE);
  70.     strcpy(infname, argv[1]);
  71.     strcpy(outfname, argv[1]);
  72.  
  73.     if (NULL == (cp = strrchr(outfname, '.'))) {
  74.         strcat(infname, ".png");
  75.     } else (*cp = '\0');
  76.     strcat(outfname, ".tif");
  77.  
  78.     if (NULL == (fp = fopen(infname, "rb")))
  79.       error_exit(ERR_READ);
  80.     err = read_PNG(fp, image);
  81.     fclose(fp);
  82.     if (0 != err) error_exit(err);
  83.  
  84.     if (NULL == (fp = fopen(outfname, "wb")))
  85.       error_exit(ERR_WRITE);
  86.     err = write_TIFF(fp, image);
  87.     fclose(fp);
  88.  
  89.     if (0 != err) error_exit(err);
  90.     return 0;
  91. }
  92.  
  93. /*
  94.  * Print warning, but continue.  A bad code should never be
  95.  * passed here, so that causes an assertion failure and exit.
  96.  */
  97.  
  98. void
  99. print_warning(
  100.     int code)
  101. {
  102.     ASSERT(PTOT_NMESSAGES > 0);
  103.     ASSERT(code >= 0 && code < PTOT_NMESSAGES);
  104.  
  105.     fprintf(stderr, "WARNING: %s.\n", ptot_error_messages[code]);
  106.     fflush(stderr);
  107. }
  108.  
  109. /*
  110.  * Print fatal error and exit.
  111.  */
  112.  
  113. void
  114. error_exit(
  115.     int code)
  116. {
  117.     int msgindex;
  118.  
  119.     ASSERT(PTOT_NMESSAGES > 0);
  120.  
  121.     if (code < 0 || code >= PTOT_NMESSAGES) msgindex = 0;
  122.     else msgindex = code;
  123.  
  124.     fprintf(stderr, "ERROR: %s.\n",
  125.       ptot_error_messages[msgindex]);
  126.     fflush(stderr);
  127.  
  128.     if (0 == code) exit(1);
  129.     else exit(code);
  130. }
  131.  
  132. void
  133. Assert(
  134.     char *filename,
  135.     int lineno)
  136. {
  137.     fprintf(stderr, "ASSERTION FAILURE: "
  138.       "Line %d of file \"%s\".\n", lineno, filename);
  139.     fflush(stderr);
  140.     exit(2);
  141. }
  142.  
  143. /*
  144.  * PNG-specific code begins here.
  145.  *
  146.  * read_PNG() reads the PNG file into the passed IMG_INFO struct.
  147.  * Returns 0 on success.
  148.  */
  149.  
  150. int
  151. read_PNG(
  152.     FILE *inf,
  153.     IMG_INFO *image)
  154. {
  155.     int err;
  156.  
  157.     ASSERT(NULL != inf);
  158.     ASSERT(NULL != image);
  159.  
  160.     memset(image, 0, IMG_SIZE);
  161.     memset(&ps, 0, sizeof ps);
  162.  
  163.     ps.inf = inf;
  164.     ps.image = image;
  165.     if (NULL == (ps.buf = (U8 *)malloc(IOBUF_SIZE)))
  166.       return ERR_MEMORY;
  167.     /*
  168.      * Skip signature and possible MacBinary header, and
  169.      * verify signature. A more robust implementation might
  170.      * search for the file signature anywhere in the first
  171.      * 1k bytes or so, but in practice, the method shown
  172.      * is adequate or file I/O applications.
  173.      */
  174.     fread(ps.buf, 1, 8, inf);
  175.     ps.buf[8] = '\0';
  176.     if (0 != memcmp(ps.buf, PNG_Signature, 8)) {
  177.         fread(ps.buf, 1, 128, inf);
  178.         ps.buf[128] = '\0';
  179.         if (0 != memcmp(ps.buf+120, PNG_Signature, 8)) {
  180.             err = ERR_BAD_PNG;
  181.             goto err_out;
  182.         }
  183.     }
  184.  
  185.     ps.got_first_chunk = ps.got_first_idat = FALSE;
  186.     do {
  187.         if (0 != (err = get_chunk_header())) goto err_out;
  188.         if (0 != (err = decode_chunk())) goto err_out;
  189.         /*
  190.          * IHDR must be the first chunk.
  191.          */
  192.         if (!ps.got_first_chunk &&
  193.           (PNG_CN_IHDR != ps.current_chunk_name))
  194.           print_warning(WARN_BAD_PNG);
  195.         ps.got_first_chunk = TRUE;
  196.         /*
  197.          * Extra unused bytes in chunk?
  198.          */
  199.         if (0 != ps.bytes_remaining) {
  200.             print_warning(WARN_EXTRA_BYTES);
  201.             if (0 != (err = skip_chunk_data())) goto err_out;
  202.         }
  203.         if (0 != (err = verify_chunk_crc())) goto err_out;
  204.  
  205.     } while (PNG_CN_IEND != ps.current_chunk_name);
  206.  
  207.     if (!ps.got_first_idat) {
  208.         err = ERR_NO_IDAT;
  209.         goto err_out;
  210.     }
  211.     if (0 != (err = validate_image(image))) goto err_out;
  212.  
  213.     ASSERT(0 == ps.bytes_remaining);
  214.     if (EOF != getc(inf)) print_warning(WARN_EXTRA_BYTES);
  215.  
  216.     err = 0;
  217. err_out:
  218.     ASSERT(NULL != ps.buf);
  219.     free(ps.buf);
  220.     return err;
  221. }
  222.  
  223. /*
  224.  * decode_chunk() is just a dispatcher, shunting the work of
  225.  * decoding the incoming chunk (whose header we have just read)
  226.  * to the appropriate handler.
  227.  */
  228.  
  229. static int
  230. decode_chunk(
  231.     void)
  232. {
  233.     /*
  234.      * Every case in the switch below should set err. We set it
  235.      * here to gurantee that we hear about it if we don't.
  236.      */
  237.     int err = ERR_ASSERT;
  238.  
  239.     switch (ps.current_chunk_name) {
  240.  
  241.     case PNG_CN_IHDR:   err = decode_IHDR();    break;
  242.     case PNG_CN_gAMA:   err = decode_gAMA();    break;
  243.     case PNG_CN_IDAT:   err = decode_IDAT();    break;
  244.     /*
  245.      * PNG allows a suggested colormap for 24-bit images. TIFF
  246.      * does not, and PLTE is not copy-safe, so we discard it.
  247.      */
  248.     case PNG_CN_PLTE:
  249.         if (ps.image->is_palette) err = decode_PLTE();
  250.         else err = skip_chunk_data();
  251.         break;
  252.  
  253.     case PNG_CN_tRNS:   err = decode_tRNS();    break;
  254.     case PNG_CN_cHRM:   err = decode_cHRM();    break;
  255.     case PNG_CN_pHYs:   err = decode_pHYs();    break;
  256.     case PNG_CN_oFFs:   err = decode_oFFs();    break;
  257.     case PNG_CN_sCAL:   err = decode_sCAL();    break;
  258.  
  259.     case PNG_CN_tEXt:   err = decode_text();    break;
  260.     case PNG_CN_zTXt:   err = decode_text();    break;
  261.  
  262.     case PNG_CN_tIME:   /* Will be recreated */
  263.     case PNG_CN_hIST:   /* Not safe to copy */
  264.     case PNG_CN_bKGD:
  265.         err = skip_chunk_data();
  266.         break;
  267.     case PNG_CN_IEND:   /* We're done */
  268.         err = 0;
  269.         break;
  270.     /*
  271.      * Note: sBIT does not have the "copy-safe" bit set, but that
  272.      * really only applies to unknown chunks. We know what it is
  273.      * just like PLTE, and that it's probably safe to put in the
  274.      * output file. hIST and bKGD are not (modifications to the
  275.      * output file might invalidate them), so we leave them out.
  276.      */
  277.     case PNG_CN_sBIT:
  278.         err = copy_unknown_chunk_data();
  279.         break;
  280.     default:
  281.         if (0 == (ps.current_chunk_name & PNG_CF_CopySafe))
  282.           err = skip_chunk_data();
  283.         else err = copy_unknown_chunk_data();
  284.         break;
  285.     }
  286.     return err;
  287. }
  288.  
  289. /*
  290.  * get_chunk_header() reads the first 8 bytes of each chunk, which
  291.  * include the length and ID fields.  It returns 0 on success.
  292.  * The crc argument is preconditioned and then updated with the
  293.  * chunk name read.
  294.  */
  295.  
  296. int
  297. get_chunk_header(
  298.     void)
  299. {
  300.     int byte;
  301.  
  302.     ASSERT(NULL != ps.inf);
  303.     ASSERT(NULL != ps.buf);
  304.  
  305.     if (8 != fread(ps.buf, 1, 8, ps.inf)) return ERR_READ;
  306.  
  307.     ps.bytes_remaining = BE_GET32(ps.buf);
  308.     ps.current_chunk_name= BE_GET32(ps.buf+4);
  309.     ps.bytes_in_buf = 0;
  310.  
  311.     if (ps.bytes_remaining > PNG_MaxChunkLength)
  312.       print_warning(WARN_BAD_PNG);
  313.  
  314.     for (byte = 4; byte < 8; ++byte)
  315.       if (!isalpha(ps.buf[byte])) return ERR_BAD_PNG;
  316.  
  317.     ps.crc = update_crc(0xFFFFFFFFL, ps.buf+4, 4);
  318.     return 0;
  319. }
  320.  
  321. /*
  322.  * get_chunk_data() reads chunk data into the buffer,
  323.  * returning the number of bytes actually read.  Do not
  324.  * use this for IDAT chunks; they are dealt with specially
  325.  * by the fill_buf() function.
  326.  */
  327.  
  328. U32
  329. get_chunk_data(
  330.     U32 bytes_requested)
  331. {
  332.     ASSERT(NULL != ps.inf);
  333.     ASSERT(NULL != ps.buf);
  334.  
  335.     ps.bytes_in_buf = (U32)fread(ps.buf, 1,
  336.       (size_t)min(IOBUF_SIZE, bytes_requested), ps.inf);
  337.  
  338.     ASSERT((S32)(ps.bytes_remaining) >= ps.bytes_in_buf);
  339.     ps.bytes_remaining -= ps.bytes_in_buf;
  340.  
  341.     ps.crc = update_crc(ps.crc, ps.buf, ps.bytes_in_buf);
  342.     return ps.bytes_in_buf;
  343. }
  344.  
  345. /*
  346.  * Assuming we have read a chunk header and all the chunk data,
  347.  * we now check to see that the CRC stored at the end of the
  348.  * chunk matches the one we've calculated.
  349.  */
  350.  
  351. int
  352. verify_chunk_crc(
  353.     void)
  354. {
  355.     ASSERT(NULL != ps.inf);
  356.     ASSERT(NULL != ps.buf);
  357.  
  358.     if (4 != fread(ps.buf, 1, 4, ps.inf)) return ERR_READ;
  359.  
  360.     if ((ps.crc ^ 0xFFFFFFFFL) != BE_GET32(ps.buf)) {
  361.         print_warning(WARN_BAD_CRC);
  362.     }
  363.     return 0;
  364. }
  365.  
  366. /*
  367.  * Read and decode IHDR. Errors that would probably cause the
  368.  * IDAT reader to fail are returned as errors; less serious
  369.  * errors generate a warning but continue anyway.
  370.  */
  371.  
  372. static int
  373. decode_IHDR(
  374.     void)
  375. {
  376.     ASSERT(NULL != ps.inf);
  377.     ASSERT(NULL != ps.buf);
  378.     ASSERT(NULL != ps.image);
  379.  
  380.     if (ps.bytes_remaining < 13) return ERR_BAD_PNG;
  381.     if (13 != get_chunk_data(13)) return ERR_READ;
  382.  
  383.     ps.image->width = BE_GET32(ps.buf);
  384.     ps.image->height = BE_GET32(ps.buf+4);
  385.  
  386.     if (0 != ps.buf[10] || 0 != ps.buf[11])
  387.       return ERR_BAD_PNG;   /* Compression & filter type */
  388.  
  389.     ps.image->is_interlaced = ps.buf[12];
  390.     if (!(0 == ps.image->is_interlaced ||
  391.       1 == ps.image->is_interlaced)) return ERR_BAD_PNG;
  392.  
  393.     ps.image->is_color = (0 != (ps.buf[9] & PNG_CB_Color));
  394.     ps.image->is_palette = (0 != (ps.buf[9] & PNG_CB_Palette));
  395.     ps.image->has_alpha = (0 != (ps.buf[9] & PNG_CB_Alpha));
  396.  
  397.     ps.image->samples_per_pixel = 1;
  398.     if (ps.image->is_color && !ps.image->is_palette)
  399.       ps.image->samples_per_pixel = 3;
  400.     if (ps.image->has_alpha) ++ps.image->samples_per_pixel;
  401.  
  402.     if (ps.image->is_palette && ps.image->has_alpha)
  403.       print_warning(WARN_BAD_PNG);
  404.     /*
  405.      * Check for invalid bit depths.  If a bitdepth is
  406.      * not one we can read, abort processing.  If we can
  407.      * read it, but it is illegal, issue a warning and
  408.      * continue anyway.
  409.      */
  410.     ps.image->bits_per_sample = ps.buf[8];
  411.  
  412.     if (!(1 == ps.buf[8] || 2 == ps.buf[8] || 4 == ps.buf[8] ||
  413.       8 == ps.buf[8] || 16 == ps.buf[8])) return ERR_BAD_PNG;
  414.  
  415.     if ((ps.buf[8] > 8) && ps.image->is_palette)
  416.       print_warning(WARN_BAD_PNG);
  417.  
  418.     if ((ps.buf[8] < 8) && (2 == ps.buf[9] || 4 == ps.buf[9] ||
  419.       6 == ps.buf[9])) return ERR_BAD_PNG;
  420.  
  421.     return 0;
  422. }
  423.  
  424. /*
  425.  * Decode gAMA chunk.
  426.  */
  427.  
  428. static int
  429. decode_gAMA(
  430.     void)
  431. {
  432.     ASSERT(NULL != ps.inf);
  433.     ASSERT(NULL != ps.buf);
  434.     ASSERT(NULL != ps.image);
  435.  
  436.     if (0 != ps.image->palette_size)
  437.       print_warning(WARN_LATE_GAMA);
  438.  
  439.     if (ps.bytes_remaining < 4) return ERR_BAD_PNG;
  440.     if (4 != get_chunk_data(4)) return ERR_READ;
  441.  
  442.     ps.image->source_gamma = (double)BE_GET32(ps.buf) / 100000.0;
  443.     return 0;
  444. }
  445.  
  446. /*
  447.  * Decode PLTE chunk. Number of entries is determined by
  448.  * chunk length. A non-multiple of 3 is technically an error;
  449.  * we just issue a warning in that case. IOBUF_SIZE must be
  450.  * 768 or greater, so we check that at compile time here.
  451.  */
  452.  
  453. #if (IOBUF_SIZE < 768)
  454. #  error "IOBUF_SIZE must be >= 768"
  455. #endif
  456.  
  457. static int
  458. decode_PLTE(
  459.     void)
  460. {
  461.     U32 bytes_read;
  462.  
  463.     ASSERT(NULL != ps.inf);
  464.     ASSERT(NULL != ps.buf);
  465.     ASSERT(NULL != ps.image);
  466.  
  467.     if (!ps.image->is_color) print_warning(WARN_PLTE_GRAY);
  468.     if (0 != ps.image->palette_size) {
  469.         print_warning(WARN_MULTI_PLTE);
  470.         return skip_chunk_data();
  471.     }
  472.     ps.image->palette_size =
  473.       min(256, (int)(ps.bytes_remaining / 3));
  474.     if (0 == ps.image->palette_size) return ERR_BAD_PNG;
  475.  
  476.     bytes_read = get_chunk_data(3 * ps.image->palette_size);
  477.     if (bytes_read < (U32)(3 * ps.image->palette_size))
  478.       return ERR_READ;
  479.  
  480.     memcpy(ps.image->palette, ps.buf, 3 * ps.image->palette_size);
  481.  
  482.     ASSERT(0 != ps.image->palette_size);
  483.     return 0;
  484. }
  485.  
  486. /*
  487.  * Copy transparency data into structure. We will later expand the
  488.  * TIFF data into full alpha to account for its lack of this data.
  489.  */
  490.  
  491. static int
  492. decode_tRNS(
  493.     void)
  494. {
  495.     int i;
  496.     U32 bytes_read;
  497.  
  498.     ASSERT(NULL != ps.inf);
  499.     ASSERT(NULL != ps.buf);
  500.     ASSERT(NULL != ps.image);
  501.  
  502.     if (ps.image->has_trns) print_warning(WARN_MULTI_TRNS);
  503.     ps.image->has_trns = TRUE;
  504.  
  505.     if (ps.image->is_palette) {
  506.         if (0 == ps.image->palette_size) {
  507.             print_warning(WARN_LATE_TRNS);
  508.         }
  509.         bytes_read = get_chunk_data(ps.bytes_remaining);
  510.         memcpy(ps.image->palette_trans_bytes,
  511.           ps.buf, (size_t)bytes_read);
  512.  
  513.         for (i = bytes_read; i < ps.image->palette_size; ++i)
  514.           ps.image->palette_trans_bytes[i] = 255;
  515.  
  516.     } else if (ps.image->is_color) {
  517.         if (ps.bytes_remaining < 6) return ERR_BAD_PNG;
  518.         bytes_read = get_chunk_data(6);
  519.         for (i = 0; i < 3; ++i)
  520.           ps.image->trans_values[i] = BE_GET16(ps.buf + 2 * i);
  521.     } else {
  522.         if (ps.bytes_remaining < 2) return ERR_BAD_PNG;
  523.         ps.image->trans_values[0] = BE_GET16(ps.buf);
  524.     }
  525.     return 0;
  526. }
  527.  
  528. static int
  529. decode_cHRM(
  530.     void)
  531. {
  532.     int i;
  533.  
  534.     ASSERT(NULL != ps.inf);
  535.     ASSERT(NULL != ps.buf);
  536.     ASSERT(NULL != ps.image);
  537.  
  538.     if (ps.bytes_remaining < 32) return ERR_BAD_PNG;
  539.     if (32 != get_chunk_data(32)) return ERR_READ;
  540.  
  541.     for (i = 0; i < 8; ++i)
  542.       ps.image->chromaticities[i] = BE_GET32(ps.buf + 4 * i);
  543.  
  544.     return 0;
  545. }
  546.  
  547. static int
  548. decode_pHYs(
  549.     void)
  550. {
  551.     ASSERT(NULL != ps.inf);
  552.     ASSERT(NULL != ps.buf);
  553.     ASSERT(NULL != ps.image);
  554.  
  555.     if (ps.bytes_remaining < 9) return ERR_BAD_PNG;
  556.     if (9 != get_chunk_data(9)) return ERR_READ;
  557.  
  558.     ps.image->resolution_unit = ps.buf[8];
  559.     if (ps.buf[8] > PNG_MU_Meter) print_warning(WARN_BAD_VAL);
  560.  
  561.     ps.image->xres = BE_GET32(ps.buf);
  562.     ps.image->yres = BE_GET32(ps.buf + 4);
  563.  
  564.     return 0;
  565. }
  566.  
  567. static int
  568. decode_oFFs(
  569.     void)
  570. {
  571.     ASSERT(NULL != ps.inf);
  572.     ASSERT(NULL != ps.buf);
  573.     ASSERT(NULL != ps.image);
  574.  
  575.     if (ps.bytes_remaining < 9) return ERR_BAD_PNG;
  576.     if (9 != get_chunk_data(9)) return ERR_READ;
  577.  
  578.     ps.image->offset_unit = ps.buf[8];
  579.     if (ps.buf[8] > PNG_MU_Micrometer) print_warning(WARN_BAD_VAL);
  580.  
  581.     ps.image->xoffset = BE_GET32(ps.buf);
  582.     ps.image->yoffset = BE_GET32(ps.buf + 4);
  583.  
  584.     return 0;
  585. }
  586.  
  587. /*
  588.  * Decode sCAL chunk. Note: as of this writing, this is not
  589.  * an official PNG chunk. It probably will be by the time
  590.  * you read this, but it might possibly change in some way.
  591.  * You have been warned. It also has no TIFF equivalent, so
  592.  * this only gets read into the structure.
  593.  */
  594.  
  595. static int
  596. decode_sCAL(
  597.     void)
  598. {
  599.     ASSERT(NULL != ps.inf);
  600.     ASSERT(NULL != ps.buf);
  601.     ASSERT(NULL != ps.image);
  602.  
  603.     get_chunk_data(ps.bytes_remaining);
  604.     if (ps.bytes_in_buf == IOBUF_SIZE) {
  605.         --ps.bytes_in_buf;
  606.         print_warning(WARN_BAD_PNG);
  607.     }
  608.     ps.buf[ps.bytes_in_buf] = '\0';
  609.  
  610.     ps.image->scale_unit = ps.buf[0];
  611.     if (ps.buf[0] < PNG_MU_Meter || ps.buf[0] > PNG_MU_Radian)
  612.       print_warning(WARN_BAD_VAL);
  613.  
  614.     ps.image->xscale = atof(ps.buf+1);
  615.     ps.image->yscale = atof(ps.buf + (strlen(ps.buf+1)) + 2);
  616.  
  617.     return 0;
  618. }
  619.  
  620. /*
  621.  * Skip all remaining data in current chunk.
  622.  */
  623.  
  624. static int
  625. skip_chunk_data(
  626.     void)
  627. {
  628.     U32 bytes_read;
  629.  
  630.     do {
  631.         bytes_read = get_chunk_data(ps.bytes_remaining);
  632.     } while (0 != bytes_read);
  633.  
  634.     return 0;
  635. }
  636.  
  637. /*
  638.  * Ensure that the image structure we have created by reading
  639.  * the input PNG is compatible with whatever we intend to do
  640.  * with it. In this case, TIFF can handle anything, so we just
  641.  * use this as a sanity check on some basic assumptions.
  642.  */
  643.  
  644. static int
  645. validate_image(
  646.     IMG_INFO *image)
  647. {
  648.     if (0 == image->width || 0 == image->height)
  649.       return ERR_BAD_IMAGE;
  650.     if (image->samples_per_pixel < 1 ||
  651.       image->samples_per_pixel > 4) return ERR_BAD_IMAGE;
  652.     if (image->is_palette && (image->palette_size < 1 ||
  653.       image->palette_size > 256)) return ERR_BAD_IMAGE;
  654.     if (NULL == image->pixel_data_file) return ERR_BAD_IMAGE;
  655.  
  656.     return 0;
  657. }
  658.  
  659. /*
  660.  * End of ptot.c.
  661.  */
  662.